package nl.ipo.cds.etl.generalization;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Semaphore;
import nl.ipo.cds.etl.util.CopyInOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.postgis.PGgeometry;
import org.postgis.binary.BinaryWriter;
import org.postgresql.copy.CopyIn;
import org.postgresql.copy.CopyManager;
import org.postgresql.core.BaseConnection;
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractorAdapter;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.WKTWriter;
public class GeneralizeWriter implements Runnable {
private static final Log logger = LogFactory.getLog(GeneralizeWriter.class);
private NativeJdbcExtractorAdapter nativeJdbcExtractorAdapter;
private BaseConnection connection;
private BlockingQueue<Event> eventQueue;
private String destination;
private String[] columnNames;
private Semaphore semaphore;
private WKTWriter wktWriter;
private BinaryWriter binaryWriter;
public GeneralizeWriter() {
semaphore = new Semaphore(0);
wktWriter = new WKTWriter();
binaryWriter = new BinaryWriter();
}
public void setDestination(String destination) {
this.destination = destination;
}
public void setConnection(Connection connection) throws SQLException {
this.connection = (BaseConnection)nativeJdbcExtractorAdapter.getNativeConnection(connection);
}
public void setEventQueue(BlockingQueue<Event> eventQueue) {
this.eventQueue = eventQueue;
}
public void setNativeJdbcExtractorAdapter(NativeJdbcExtractorAdapter nativeJdbcExtractorAdapter) {
this.nativeJdbcExtractorAdapter = nativeJdbcExtractorAdapter;
}
public void setColumnNames(String[] columnNames) {
this.columnNames = columnNames;
}
@Override
public void run() {
logger.debug("starting");
try {
CopyManager copyManager = new CopyManager(connection);
StringBuilder queryBuilder = new StringBuilder("copy ");
queryBuilder.append(destination);
queryBuilder.append(" (");
for(int i = 0; i < columnNames.length; i++) {
if(i != 0) {
queryBuilder.append(", ");
}
queryBuilder.append(columnNames[i]);
}
if(columnNames.length > 0) {
queryBuilder.append(", ");
}
queryBuilder.append("geometry) from stdin csv");
CopyIn copyIn = copyManager.copyIn(queryBuilder.toString());
CopyInOutputStream outputStream = new CopyInOutputStream(copyIn);
Writer writer = new OutputStreamWriter(outputStream, "utf-8");
PrintWriter printWriter = new PrintWriter(writer);
logger.debug("database connection established");
long featureCounter = 0;
for(;;) {
Event event = eventQueue.take();
logger.debug("event received");
if(event instanceof GeometryResult) {
GeometryResult geometryResult = (GeometryResult)event;
Geometry geometry = geometryResult.getGeometry();
String[] columnValues = geometryResult.getColumnValues();
for(int i = 0; i < geometry.getNumGeometries(); i++) {
String wkt = wktWriter.write(geometry.getGeometryN(i));
org.postgis.Geometry pgGeometry = PGgeometry.geomFromString(wkt);
pgGeometry.setSrid(28992);
featureCounter++;
for(int j = 0; j < columnValues.length; j++) {
if(j != 0) {
printWriter.print(',');
}
String columnValue = columnValues[j];
if(columnValue != null) {
printWriter.print('"');
printWriter.print(columnValue);
printWriter.print('"');
}
}
if(columnValues.length > 0) {
printWriter.print(',');
}
printWriter.print('"');
printWriter.print(binaryWriter.writeHexed(pgGeometry));
printWriter.println('"');
}
semaphore.release();
logger.debug("geometry received (" + semaphore.availablePermits() + ")");
} else if(event instanceof Finalize) {
logger.debug("finalize event received");
break;
} else {
logger.debug("Unknown event type: " + event.getClass().getCanonicalName());
}
}
printWriter.close();
logger.debug("finished: " + featureCounter + " geometries written");
semaphore.release();
} catch(Exception e) {
logger.debug("couldn't write generalized geometrie", e);
}
}
public void join(int counter) throws InterruptedException {
logger.debug("join called with counter: " + counter + " available: " + semaphore.availablePermits());
semaphore.acquire(counter);
}
public void join() throws InterruptedException {
join(1);
}
}